package com.ruoyi.platform.system.role.manager;

import com.ruoyi.base.enums.ExceptionEnum;
import com.ruoyi.base.exception.SysException;
import com.ruoyi.base.redis.role.UserMenuRedis;
import com.ruoyi.base.service.BaseService;
import com.ruoyi.base.utils.thread.ThreadUtils;
import com.ruoyi.platform.system.menu.enums.MenuEnum;
import com.ruoyi.platform.system.menu.manager.MenuManager;
import com.ruoyi.platform.system.menu.pojo.MenuTreeDTO;
import com.ruoyi.platform.system.role.dao.RoleRdbDAO;
import com.ruoyi.platform.system.role.dao.menu.RoleMenuRdbDAO;
import com.ruoyi.platform.system.role.enums.RoleIdEnum;
import com.ruoyi.platform.system.role.pojo.RoleDO;
import com.ruoyi.platform.system.role.pojo.menu.RoleMenuDO;
import com.ruoyi.platform.system.user.dao.role.UserRoleDAO;
import com.ruoyi.platform.system.user.pojo.role.UserRoleDO;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 角色
 *
 * @author lcf
 */
@Component
public class RoleManager extends BaseService {
    @Autowired
    private RoleMenuRdbDAO roleMenuRdbDAO;
    @Autowired
    private RoleRdbDAO roleRdbDAO;
    @Autowired
    private UserRoleDAO userRoleRdbDAO;
    @Autowired
    private UserMenuRedis userMenuRedis;

    /**
     * 获取角色菜单权限树
     */
    public List<MenuTreeDTO> getRoleMenuTree(List<Long> roleIdList) {
        if (CollectionUtils.isEmpty(roleIdList)) {
            return MenuManager.getMenuList();
        }

        //超级管理员
        if (roleIdList.contains(RoleIdEnum.SUPER_ADMIN.getRoleId())) {
            List<MenuEnum> menuList = Arrays.stream(MenuEnum.values()).collect(Collectors.toList());
            return MenuManager.getMenuList(menuList);
        }

        List<RoleMenuDO> list = roleMenuRdbDAO.selectByRoleIdList(roleIdList);
        if (CollectionUtils.isEmpty(list)) {
            return MenuManager.getMenuList();
        }

        List<MenuEnum> menuList = list.stream().map(x -> MenuEnum.ofCode(x.getMenuCode())).filter(Objects::nonNull).collect(Collectors.toList());
        return MenuManager.getMenuList(menuList);
    }

    /**
     * 获取用户角色列表
     */
    public List<UserRoleDO> getUserRoleList(long userId) {
        return userRoleRdbDAO.selectByUserIdList(Collections.singletonList(userId));
    }

    /**
     * 检查是否有角色
     */
    public boolean checkHasAnyRole(long userId, RoleIdEnum... roleIdEnum) {
        List<UserRoleDO> userRoleList = getUserRoleList(userId);
        if (CollectionUtils.isEmpty(userRoleList)) {
            return false;
        }

        if (roleIdEnum == null || roleIdEnum.length == 0) {
            return false;
        }

        return userRoleList.stream().anyMatch(x -> Arrays.stream(roleIdEnum).anyMatch(y -> Objects.equals(x.getRoleId(), y.getRoleId())));
    }

    /**
     * 刷新已登陆用户权限
     */
    public void refreshCurrentUserPermissionByRoleId(long roleId) {
        List<UserRoleDO> userRoleList = userRoleRdbDAO.selectByRoleId(roleId);
        if (CollectionUtils.isNotEmpty(userRoleList)) {
            ThreadUtils.addTask(() -> {
                List<Long> userIdList = userRoleList.stream().map(UserRoleDO::getUserId).collect(Collectors.toList());
                userIdList.forEach(x -> userMenuRedis.refreshIfExist(x));
            });
        }
    }

    /**
     * 检查是否系统角色
     */
    public void checkSysRole(long roleId) {
        if (Arrays.stream(RoleIdEnum.values()).anyMatch(x -> Objects.equals(roleId, x.getRoleId()))) {
            throw new SysException(ExceptionEnum.CAN_NOT_EDIT_SYS_ROLE);
        }
    }

    /**
     * 检查是否超级管理员角色
     */
    public void checkSuperRole(long roleId) {
        if (roleId == RoleIdEnum.SUPER_ADMIN.getRoleId()) {
            throw new SysException(ExceptionEnum.CAN_NOT_EDIT_SYS_ROLE);
        }
    }

    /**
     * 检查角色id
     */
    public RoleDO checkRoleId(long roleId) {
        return getOrThrow(() -> roleRdbDAO.selectRoleByPrimaryKey(roleId), ExceptionEnum.ROLE_NOT_EXIST);
    }
}
